﻿// -------------------------------------------------------------------------
//    @FileName         :    NFMapPart.cpp
//    @Author           :    gaoyi
//    @Date             :    24-8-30
//    @Email            :    445267987@qq.com
//    @Module           :    NFMapPart
//
// -------------------------------------------------------------------------

#include "NFMapPart.h"

#include <CityDescEx.h>
#include <NFMapUtil.h>
#include <NFPlayer.h>
#include <DescStore/CityMapDesc.h>

#include "proto_db.pb.h"
#include "proto_event.nanopb.h"
#include "proto_event.pb.h"
#include "NFComm/NFCore/NFRandom.hpp"
#include "NFLogicCommon/NFCommMacros.h"

NFMapPart::NFMapPart()
{
    if (EN_OBJ_MODE_INIT == NFShmMgr::Instance()->GetCreateMode())
    {
        CreateInit();
    }
    else
    {
        ResumeInit();
    }
}

NFMapPart::~NFMapPart()
{
}

int NFMapPart::CreateInit()
{
    m_iCitySyncSeq = 0;
    m_iCityCurSeq = 0;
    m_bInSync = false;

    SetEnterCity(false);
    m_bInTransMap = false;
    m_iMapInstId = INVALID_ID;
    m_bStateLeave = false;
    m_iRoleObjID = INVALID_ID;
    return 0;
}

int NFMapPart::ResumeInit()
{
    return 0;
}

int NFMapPart::LoadFromDB(const proto_ff::tbRoleDetail* pDbData)
{
    CHECK_NULL(0, pDbData);
    m_stMapData.FromPb(pDbData->role_play_data().map_data());
    m_stCityEnterData.FromPb(pDbData->role_play_data().city_enter_data());
    SetEnterCity(false);
    return 0;
}

int NFMapPart::InitConfig(proto_ff::tbRoleDetail* pDbData, const RoleOne& stRoleOne)
{
    CHECK_NULL(0, pDbData);
    auto pRoleMapData = pDbData->mutable_role_play_data()->mutable_map_data();
    CHECK_NULL(0, pRoleMapData);

    constexpr int defaultEnterMapId = 11;
    pRoleMapData->set_map_desc_id(defaultEnterMapId);

    const CCityMapData* pCityMapDesc = CityDescEx::Instance()->GetCityMapData(defaultEnterMapId);
    CHECK_NULL(0, pCityMapDesc);

    auto pstMapDataDesc = pCityMapDesc->GetMapData();
    auto pstHeroSpawnOne = &pstMapDataDesc->hero_spawn_list[1];
    int iX = pstHeroSpawnOne->x + RangeRand(0, VECTOR3_MULTI * 2) - VECTOR3_MULTI;
    int iY = pstHeroSpawnOne->y + RangeRand(0, VECTOR3_MULTI * 2) - VECTOR3_MULTI;

    pRoleMapData->set_direction(pstHeroSpawnOne->direction);
    pRoleMapData->mutable_pos()->set_x(iX);
    pRoleMapData->mutable_pos()->set_y(iY);
    pRoleMapData->mutable_pos()->set_z(pstHeroSpawnOne->z);

    pDbData->mutable_role_play_data()->mutable_city_enter_data();
    return 0;
}

int NFMapPart::SaveDB(proto_ff::tbRoleDetail* pDbData)
{
    CHECK_NULL(0, pDbData);
    m_stMapData.ToPb(pDbData->mutable_role_play_data()->mutable_map_data());
    m_stCityEnterData.ToPb(pDbData->mutable_role_play_data()->mutable_city_enter_data());
    return 0;
}

int NFMapPart::MakePlayerDataCS(proto_ff::Proto_CSGetRoleRsp* pCsGetRoleRsp)
{
    CHECK_NULL(0, pCsGetRoleRsp);
    auto pMapData = pCsGetRoleRsp->mutable_map_data();
    CHECK_NULL(0, pMapData);

    auto pPlayer = GetPlayer();
    CHECK_NULL(0, pPlayer);

    if (0 != NFMapUtil::CheckEnterMap(pPlayer, m_stMapData.map_desc_id))
    {
        m_stMapData.map_desc_id = DEFAULT_ENTER_CITY_MAP_ID;
        /*CPlayerTeam* pPlayerTeam = pPlayer->GetPlayerTeam();
        if (pPlayerTeam)
        {
            CPlayerTeamUtil::PlayerQuitTeam(pPlayer, proto_ff::CS_TEAM_NOTIFY_EVENT_KICK);
        }*/
    }

    m_stMapData.ToPb(pMapData);

    auto pCityEnterData = pCsGetRoleRsp->mutable_city_enter_data();
    CHECK_NULL(0, pCityEnterData);
    m_stCityEnterData.ToPb(pCityEnterData);
    return 0;
}

int NFMapPart::MakeCityPlayerData(proto_ff::CityRoleInfo* pGcCityRoleInfo)
{
    CHECK_NULL(0, pGcCityRoleInfo);
    m_stMapData.ToPb(pGcCityRoleInfo->mutable_map_data());
    return 0;
}

void NFMapPart::SetEnterCity(bool bSet)
{
    m_bEnterCity = bSet;
}

bool NFMapPart::IsEnterCity() const
{
    return m_bEnterCity;
}

void NFMapPart::SetStateLeave(bool bSet)
{
    m_bStateLeave = bSet;
}

bool NFMapPart::IsStateLeave() const
{
    return m_bStateLeave;
}

void NFMapPart::MarkCitySynDirty()
{
    ++m_iCityCurSeq;
}

bool NFMapPart::IsNeedSyn2City() const
{
    return m_iCityCurSeq > m_iCitySyncSeq;
}

bool NFMapPart::IsInCitySyn() const
{
    return m_bInSync;
}

void NFMapPart::SetCitySyn(bool bSet)
{
    m_bInSync = bSet;
}

int NFMapPart::GetCurSynSeq() const
{
    return m_iCityCurSeq;
}

void NFMapPart::SetSynSeq(int iSynSeq)
{
    m_iCitySyncSeq = iSynSeq;
}

int NFMapPart::GetMapInstId() const
{
    return m_iMapInstId;
}

void NFMapPart::SetMapInstId(int iMapInstId)
{
    m_iMapInstId = iMapInstId;
}

const RoleMapData* NFMapPart::GetMapData() const
{
    return &m_stMapData;
}

RoleMapData* NFMapPart::GetMapData()
{
    return &m_stMapData;
}

void NFMapPart::SetInTransMap(bool bSet)
{
    m_bInTransMap = bSet;
}

bool NFMapPart::IsInTransMap() const
{
    return m_bInTransMap;
}

void NFMapPart::SetRoleObjID(int iObjID)
{
    m_iRoleObjID = iObjID;
}

int NFMapPart::GetRoleObjID()
{
    return m_iRoleObjID;
}

int NFMapPart::LogicTick()
{
    if (IsNeedSyn2City() && !IsInCitySyn())
    {
        auto pPlayer = GetPlayer();
        CHECK_NULL(0, pPlayer);

        NFMapUtil::SynCityRoleInfo(pPlayer);
    }

    return 0;
}

int NFMapPart::OnLogin()
{
    SetEnterCity(false);
    SetStateLeave(false);

    auto pPlayer = GetPlayer();
    CHECK_NULL(0, pPlayer);

    proto_ff::Proto_CSReq oCSReq;
    proto_ff::Proto_CSMapQueryReq *pMapQueryReq = oCSReq.mutable_map_query_req();
    pMapQueryReq->set_map_desc_id(m_stMapData.map_desc_id);
    pMapQueryReq->set_trans_npc_id(0);
    NFMapUtil::StartEnterMap(pPlayer, oCSReq);
    return 0;
}

int NFMapPart::AddEnterCity(int iMapId)
{
    m_stCityEnterData.enter_map_id.insert(iMapId);
    return 0;
}

bool NFMapPart::FindEnterCity(int iMapId)
{
    auto iter = m_stCityEnterData.enter_map_id.find(iMapId);
    if (iter != m_stCityEnterData.enter_map_id.end())
    {
        return true;
    }

    return false;
}

int NFMapPart::SynMapData(const proto_ff::RoleMapData* pRoleMapData)
{
    auto pPlayer = GetPlayer();
    CHECK_NULL(0, pPlayer);

    // 最后一次同步，跟玩家上线有时候坐标有点误差
    int xAbs = abs(pRoleMapData->pos().x() - m_stMapData.pos.x);
    int yAbs = abs(pRoleMapData->pos().y() - m_stMapData.pos.y);
    int zAbs = abs(pRoleMapData->pos().z() - m_stMapData.pos.z);
    if (pRoleMapData->map_desc_id() != m_stMapData.map_desc_id || xAbs > 1 || yAbs > 1 || zAbs > 1)
    {
        LOG_TRACE(pPlayer->GetRoleID(), "sync map data:x:{} y:{} z:{}", pRoleMapData->pos().x(), pRoleMapData->pos().y(), pRoleMapData->pos().z());
        FireExecute(NF_ST_LOGIC_SERVER, EVENT_SYNC_MAP_DATA, EVENT_SRC_TYPE_PLAYER, pPlayer->GetRoleID(), *pRoleMapData);
    }

    m_stMapData.FromPb(*pRoleMapData);

    NFMapUtil::CheckAreaInfo(pPlayer);
    MarkDirty();
    return 0;
}
